Published on

Environment Property Wrapper In SwiftUI

Authors

什么是@Environment?

A property wrapper that reads a value from a view's environment 从视图的环境变量中读取一个属性包装的值

Overview

Use the Environment property wrapper to read a value stored in a view's environment. Indicate the value to read using an EnvironmnetValues key path in the property declarations. 在属性声明中使用EnvironmnetValues键路径来指示要读取的值。

For example, you can create a property that reads the color scheme of the current view using the key path of the colorScheme property: 例如,你可以创建一个属性,使用colorScheme属性的键路径来读取当前视图的颜色方案:

@Environment(\.colorScheme) var colorScheme: ColorScheme

You can condition a view's content on the associated value, which you read from the declared property's wrappedValue.

As with any property wrapper, you access the wrapped value by directly referring to the property:

if colorScheme == .dark {
    DrarkContent()
} else {
    LightContent()
}

If the value changes, SwiftUI updates any parts of your view that depend on the value. For example, that might happen in the above example if the user Appeareance settings. 当某个值发生变化时,SwiftUI 会自动更新视图中依赖于这个值的所有部分。比如,在前述例子中,如果用户改变了他们的外观设置,这种更新就会发生。

You can use this property wrapper to read - but not set - an environment value. SwiftUI updates some environment values automatically based on system settings and provides reasonable defaults for others. You can override some of these, as well as set custom environment vlaues that you define, using the environments(::) view modifier. 你可以利用这个属性包装器来读取(而非设定)一个环境值。SwiftUI 会根据系统设置自动更新一些环境值,并为其它值提供合适的默认设置。你可以通过使用 environments(::) 视图修饰符来覆盖部分环境值,或者设定你自己定义的环境值。

For the complete list of environment values provided by SwiftUI, see the properties of the EnvironmentValues structure. For information about creating custom environment values, see the EnvironmentKey protocol. 如果想要查看 SwiftUI 提供的所有环境值,请参考 EnvironmentValues 结构体中的属性。关于如何创建自定义环境值,可以参见 EnvironmentKey 协议的相关信息。

Get an observable object

You can also use Environment to get an observable object from a view's environment. The observable object must conform to the Observable protocol, and your app must set the object in environment using the object itself or a key path. To see the object in the environment using the object itself, use the environment(:) modifer: 你还可以利用 Environment 从视图的环境里提取一个可观察对象。这个对象必须遵循 Observable 协议,并且你的应用需要通过对象本身或其键路径来在环境中设置此对象。 为了通过对象本身在环境中观察这个对象,你可以使用 environment(:) 修饰符:

@Observable
Class Library {
    var books: [Book] = [Book(), Book(), Book()]

    var availableBooksCount: Int {
        books.filter(\.isAvailable).count
    }
}

@main
struct BookReaderApp: App {
    @State private var library = Library()

    var body: some Scene {
        WindowGroup {
            LibraryView()
            .environment(library)
        }
    }
}

To get the observable object using its type, create a property and provide the Environment property wrapper the object's type: 要通过对象的类型来获取这个可观察对象,你需要先定义一个属性,然后为 Environment 的属性包装器指定这个对象的类型:

struct LibraryView: View {
    @Environment(Library.self) private var library

    var body: some View {
        // ...
    }
}

By default, reading an object from the environment returns a non-optional object when using the object type as the key. This default behavior assumes that a view in the current hierarchy previously stored a non-optional instance of the type using the environment(_:) modifier. If a view attempts to retrieve an object using its type and that object isn't in the environment, SwiftUI throws an exception. 默认情况下,若使用对象的类型作为键从环境中读取数据,会得到一个非可选类型的对象。这是基于一个假设:在当前的视图层级中,已经有视图使用 environment(_:) 修饰符存储了这种类型的非可选实例。如果视图试图通过类型来获取一个不存在于环境中的对象,SwiftUI 将会抛出异常。

In cases where is no guarantee that an object is in the environment, retrieve an optional version of the object as shown in the following code. If the object isn't avaiable the environment, SwiftUI returns nil instead of throwing an exception. 在无法确保环境中存在某个对象的情况下,应该尝试获取该对象的可选版本,正如下面的代码展示的那样。这样做的话,如果环境中没有该对象,SwiftUI 将返回 nil,而不是抛出异常。

@Environment(Library.self) private var library: Library?

Get an observable object using a key path

To set the object with a key path, use the environment(_:_:) modifier: 要使用键路径来设置对象,可以应用 environment(::) 修饰符:

@Observable
class Library {
    var books: [Book] = [Book(), Book(), Book()]

    var availableBooksCount: Int {
        books.filter(\.isAvailable).count
    }
}

@main
struct BookReaderApp: App {
    @State private var library = Library()
    var body: some Scene {
        WindowGroup {
            LibraryView()
            .environment(\.library, library)
        }
    }
}

To get the object, create a propery and specify the key path: 要取得对象,需先定义一个属性,然后明确指定键路径:

struct LibraryView: View {
    @Environment(\.library) private var library

    var body: some View {
        // ...
    }
}